class IUP_FILE_DIALOG
-- Creates the File Dialog element. It is a predefined dialog for selecting 
-- files or a directory.
--
-- This a native pre-defined dialog that is not altered by IupSetLanguage.
--
-- In Windows, the FILE and the DIRECTORY attributes also accept strings 
-- containing "/" as path separators, but the VALUE attribute will always 
-- return strings using the "\" character.
-- 
-- In Windows, the dialog will be modal relative only to its parent or to the 
-- active dialog. 
-- 
-- In Windows, when using UTF-8 strings (UTF8MODE=True), attributes that return 
-- file names are still using the current locale, because the standard file I/O 
-- functions, like fopen, use ANSI file names. To use UTF-8 filenames (that can 
-- be lately be converted to UTF-16) set the global attribute UTF8MODE_FILE to 
-- True.	In a specific case, the application can set before popup, and unset 
-- after, so for just that call will return in UTF-8.
-- 
-- When saving a file, the overwrite check is done before the FILE_CB callback 
-- is called with status=OK. If the application wants to add an extension to 
-- the file name inside the FILE_CB callback when status=OK, then it must 
-- manually check if the file with the extension exits and asks the user if the 
-- file should be replaced, if not then the callback can set the FILE attribute 
-- and returns IUP_CONTINUE, so the file dialog will remain open and the user 
-- will have an opportunity to change the file name now that it contains the 
-- extension.	

inherit
	IUP_WIDGET
		redefine
			execute_help,
			execute_file,
			execute_button,
			execute_motion,
			execute_wheel
		end
	IUP_WIDGET_TITLE
	IUP_WIDGET_POPUP
	IUP_WIDGET_ICON
	IUP_WIDGET_PARENT_DIALOG

create {ANY}
   file_dialog
	
feature {ANY}

	file_dialog
		local
			a_file_dialog: POINTER
		do
			a_file_dialog := int_file_dialog
			set_widget(a_file_dialog)
		end

	-- Attributes

	set_allow_new (state: BOOLEAN)
		-- Indicates if non-existent file names are accepted. If equals "False" 
		-- and the user specifies a non-existing file, an alert dialog is shown. 
		-- Default: if the dialog is of type "OPEN", default is "False"; if the 
		-- dialog is of type "SAVE", default is "True". Not used when 
		-- DIALOGTYPE=DIR.	
		do
			iup_open.set_attribute(Current, "ALLOWNEW", boolean_to_yesno(state))
		end

	set_dialog_type (type: STRING)
		-- Type of dialog (Open, Save or Directory). Can have values "OPEN", 
		-- "SAVE" or "DIR". Default: "OPEN".
		--
		-- In Windows, when DIALOGTYPE=DIR the dialog shown is not the same 
		-- dialog for OPEN and SAVE, this new dialog does not have the Help 
		-- button neither filters. Also this new dialog needs CoInitializeEx with 
		-- COINIT_APARTMENTTHREADED (done in iup_open), if the COM library was 
		-- initialized with COINIT_MULTITHREADED prior to iup_open then the new 
		-- dialog will have limited functionality. In Motif or GTK the dialog is 
		-- the same, but it only allows the user to select a directory. 
		require
			is_valid_type(type)
		do
			iup_open.set_attribute(Current, "DIALOGTYPE", type)
		end

	set_directory (dir: STRING)
		-- Initial directory. When set the last separator does not need to be 
		-- specified, but when get the returned value will always contains the 
		-- last separator.
		--
		-- In Motif or GTK, if not defined, the dialog opens 
		-- in the current directory.
		--
		-- In Windows, if not defined and the application has used the dialog in 
		-- the past, the path most recently used is selected as the initial 
		-- directory. However, if an application is not run for a long time, its 
		-- saved selected path is discarded. Also if not defined and the current 
		-- directory contains any files of the specified filter types, the 
		-- initial directory is the current directory. Otherwise, the initial 
		-- directory is the "My Documents" directory of the current user. 
		-- Otherwise, the initial directory is the Desktop folder.
		do
			iup_open.set_attribute(Current, "DIRECTORY", dir)
		end

	get_directory: STRING
		-- When consulted after the dialog is closed and the user pressed the 
		-- OK button, it will contain the directory of the selected file. The 
		-- returned value will always contains the last separator.
		do
			Result := iup_open.get_attribute(Current, "DIRECTORY")
		end

	set_ext_filter (filter: STRING)
		-- [Windows and GTK Only]: Defines several file filters. It has priority 
		-- over FILTERINFO and FILTER. Must be a text with the format 
		-- "FilterInfo1|Filter1|FilterInfo2|Filter2|...". The list ends with 
		-- character '|'. Example: "Text files|*.txt;*.doc|Image 
		-- files|*.gif;*.jpg;*.bmp|". In GTK there is no way how to overwrite the 
		-- filters, so it is recommended to always add a less restrictive filter 
		-- to the filter list, for example "All Files|*.*".
		do
			iup_open.set_attribute(Current, "EXTFILTER", filter)
		end

	set_ext_default (ext: STRING)
		-- Default extension to be used if selected file does not have an 
		-- extension. The inspected extension will consider to have the same 
		-- number of characters of the default extension. It must NOT include the 
		-- period ".".
		do
			iup_open.set_attribute(Current, "EXTDEFAULT", ext)
		end

	set_file (file: STRING)
		-- Name of the file initially shown in the "File Name" field in the 
		-- dialog. If contains a full path, then it is used as the initial 
		-- directory and DIRECTORY is ignored.
		do
			iup_open.set_attribute(Current, "FILE", file)
		end

	file_exist: BOOLEAN
		-- Indicates if the file defined by the FILE attribute exists or not. It 
		-- is only valid if the user has pressed OK in the dialog. Not set when 
		-- DIALOGTYPE=DIR or MULTIPLEFILES=True.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "FILEEXIST")
			Result := yesno_to_boolean(str)
		end

	set_filter (filter: STRING)
		-- String containing a list of file filters separated by ';' without 
		-- spaces. Example: "*.C;*.LED;test.*". In Motif only the first filter is 
		-- used.
		do
			iup_open.set_attribute(Current, "FILTER", filter)
		end

	set_filter_info (info: STRING)
		-- [Windows and GTK Only]: Filter's description. If not defined the 
		-- filter itself will be used as its description. String containing a 
		-- list of file filters separated by ';'.
		do
			iup_open.set_attribute(Current, "FILTERINFO", info)
		end

	set_filter_used (id: INTEGER)
		-- [Windows and GTK Only]: the index of the filter in EXTFILTER to use 
		-- starting at 1. Set only if EXTFILTER is defined.
		require
			id >= 1
		do
			iup_open.set_attribute(Current, "FILTERUSED", id.to_string)
		end

	get_filter_used: INTEGER
		-- It returns the selection made by the user.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "FILTERUSED")

			if str.is_integer then
				Result := str.to_integer
			end
		end

	set_multiple_files (state: BOOLEAN)
		-- When "True", this attribute allows the user to select multiple files 
		-- when DIALOGTYPE=OPEN. The value returned by VALUE is to be changed the 
		-- following way: the directory and the files are passed separately, in 
		-- this order. The character used for separating the directory and the 
		-- files is '|'. The file list ends with character '|'. When the user 
		-- selects just one file, the directory and the file are not separated by 
		-- '|'. For example:
		--
		-- "/tecgraf/iup/test|a.txt|b.txt|c.txt|" or
		-- "/tecgraf/iup/test/a.txt" (only one file is selected)
		do
			iup_open.set_attribute(Current, "MULTIPLEFILES",
										  boolean_to_yesno(state))
		end

	set_no_change_dir (state: BOOLEAN)
		-- Indicates if the current working directory must be restored after the 
		-- user navigation. Default: "True".
		do
			iup_open.set_attribute(Current, "NOCHANGEDIR",
										  boolean_to_yesno(state))	
		end

	set_no_overwrite_prompt (state: BOOLEAN)
		-- Do not prompt to overwrite an existent file when in "SAVE" dialog. 
		-- Default is "False", i.e. prompt before overwrite.  
		do
			iup_open.set_attribute(Current, "NOOVERWRITEPROMPT",
										  boolean_to_yesno(state))	
		end

	set_no_places_bar (state: BOOLEAN)
		-- [Windows Only]: do not show the places bar. 
		do
			iup_open.set_attribute(Current, "NOPLACESBAR", boolean_to_yesno(state))
		end

	set_show_edit_box (state: BOOLEAN)
		-- [Windows Only]: Show an edit box in a dialog selection dialog. (since 
		-- 3.20). Default: False.
		do
			iup_open.set_attribute(Current, "SHOWEDITBOX",
										  boolean_to_yesno(state))
		end

	set_show_hidden (state: BOOLEAN)
		-- Show hidden files. Default: False.
		do
			iup_open.set_attribute(Current, "SHOWHIDDEN",
										  boolean_to_yesno(state))
		end

	-- set_show_preview

	get_status: INTEGER
		-- Indicates the status of the selection made:
		--
		-- "1": New file.
      -- "0": Normal, existing file or directory.
      -- "-1": Operation cancelled.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "STATUS")

			if str.is_integer then
				Result := str.to_integer
			end
		end

	get_value: STRING
			-- Name of the selected file(s), or Void if no file was selected. When 
			-- MULTIPLEFILES=True it contains the path and several file names 
			-- separated by the '|' character.
		local
			sf: STRING
		do
			create sf.from_external_copy(iup_open.get_attribute(Current, "VALUE").to_external)
			Result := sf
		end

	get_multivalue_count: INTEGER
		-- Number of returned values when MULTIPLEFILES=True. It includes the 
		-- path.
		local
			str: STRING
		do
			str := iup_open.get_attribute(Current, "MULTIVALUECOUNT")

			if str.is_integer then
				Result := str.to_integer
			end
		end

	get_multivalue_at (id: INTEGER): STRING
		-- Almost the same sequence returned in VALUE when MULTIPLEFILES=Yes but 
		-- split in several attributes. VALUE0 contains the path (same value 
		-- returned in DIRECTORY), and VALUE1,VALUE2,... contains each file name 
		-- without the path.
		require
			id >= 0
		do
			Result := iup_open.get_attribute_id(Current, "MULTIVALUE", id)
		end
	
	set_multivalue_path (state: BOOLEAN)
		-- Force a full path in VALUE attribute when MULTIPLEFILES=True (id=0 will
		-- still contains the path of the first file). In Windows and Motif, only 
		-- files in the same folder may be selected, but in GTK when using the 
		-- "Recent Files" files from different folders can be selected. (since 
		-- 3.20)	
		do
			iup_open.set_attribute(Current, "MULTIVALUEPATH",
										  boolean_to_yesno(state))
		end

	-- Callbacks

	set_cb_help (act: PROCEDURE[TUPLE[IUP_FILE_DIALOG]])
		-- Action generated when the user press F1 at a control. In Motif 
		-- is also activated by the Help button in some workstations 
		-- keyboard.
		-- Returns: IUP_CLOSE will be processed.
		local
			operation: INTEGER
		do
			cb_help := act

			if cb_help /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "HELP_CB", "NONEEDED", operation)
		end

	set_cb_file (act: FUNCTION[TUPLE[IUP_FILE_DIALOG, STRING, STRING], STRING])
		-- Action generated when a file is selected. Not called when 
		-- DIALOGTYPE=DIR. When MULTIPLEFILES=True it is called only for one 
		-- file. Can be used with SHOWPREVIEW=False also.
		local
			operation: INTEGER
		do
			cb_file := act

			if cb_file /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "FILE_CB", "NONEEDED", operation)
		end

	set_cb_button (act: FUNCTION[TUPLE[IUP_FILE_DIALOG, INTEGER, INTEGER, INTEGER, INTEGER, STRING], STRING])
		-- Action generated when any mouse button is pressed or released over the 
		-- preview canvas. Both calls occur before the ACTION callback when 
		-- button 1 is being used.
		--
		-- IUP_CANVAS: identifies the element that activated the event.
		-- button: identifies the activated mouse button:
		--
		-- 1 - left mouse button (button 1);
		-- 2 - middle mouse button (button 2);
		-- 3 - right mouse button (button 3).
		--
		-- pressed: indicates the state of the button:
		--
		-- 0 - mouse button was released;
		-- 1 - mouse button was pressed.
		-- 
		-- x, y: position in the canvas where the event has occurred, in pixels.
		--
		-- status: status of the mouse buttons and some keyboard keys at the 
		-- moment the event is generated. The following IUP features must be used 
		-- for verification:
		--
		-- is_shift(status)
		-- is_control(status)
		-- is_button_1(status)
		-- is_button_2(status)
		-- is_button_3(status)
		-- is_button_4(status)
		-- is_button_5(status)
		-- is_double(status)
		-- is_alt(status)
		-- is_sys(status)
		--
		-- Returns: IUP_CLOSE will be processed. On some controls if IUP_IGNORE 
		-- is returned the action is ignored (this is system dependent).	
		local
			operation: INTEGER
		do
			cb_button := act

			if cb_button /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "BUTTON_CB", "NONEEDED", operation)
		end

	set_cb_motion (act: FUNCTION[TUPLE[IUP_FILE_DIALOG, INTEGER, INTEGER, STRING], STRING])
		-- Action generated when the mouse is moved over the preview canvas.
		-- ih: identifier of the element that activated the event.
		-- x, y: position in the canvas where the event has occurred, in pixels.
		-- status: status of mouse buttons and certain keyboard keys at the 
		-- moment the event was generated. The same macros used for BUTTON_CB can 
		-- be used for this status.
		local
			operation: INTEGER
		do
			cb_motion := act

			if cb_motion /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "MOTION_CB", "NONEEDED", operation)
		end

	set_cb_wheel (act: FUNCTION[TUPLE[IUP_FILE_DIALOG, REAL_32, INTEGER, INTEGER, STRING], STRING])
		-- Action generated when the mouse wheel is rotated over the preview 
		-- canvas. If this callback is not defined the wheel will automatically 
		-- scroll the canvas in the vertical direction by some lines, the 
		-- SCROLL_CB callback if defined will be called with the IUP_SBDRAGV 
		-- operation.	
		--
		-- ih: identifier of the element that activated the event.
		-- delta: the amount the wheel was rotated in notches.
		-- x, y: position in the canvas where the event has occurred, in pixels.
		-- status: status of mouse buttons and certain keyboard keys at the 
		-- moment the event was generated. The same macros used for BUTTON_CB can 
		-- be used for this status.
		--
		-- In Motif and GTK delta is always 1 or -1. In Windows is some 
		-- situations delta can reach the value of two. In the future with more 
		-- precise wheels this increment can be changed.
		local
			operation: INTEGER
		do
			cb_wheel := act

			if cb_wheel /= Void then
				operation := 1
			else
				operation := 0
			end
			
			iup_open.set_callback (Current, "WHEEL_CB", "NONEEDED", operation)
		end

feature {IUP}

	-- Common callbacks

	execute_help
		do
			cb_help.call([Current])
		end

	-- Extra

	execute_file (file_name, status: STRING): STRING
		do
			Result := cb_file.item([Current, file_name, status])
		end

	execute_button (btn, pressed, x, y: INTEGER; status: STRING): STRING
		do
			Result := cb_button.item([Current, btn, pressed, x, y, status])
		end

	execute_motion (x, y: INTEGER; status: STRING): STRING
		do
			Result := cb_motion.item([Current, x, y, status])
		end

	execute_wheel (delta: REAL_32; x, y: INTEGER; status: STRING): STRING
		do
			Result := cb_wheel.item([Current, delta, x, y, status])
		end

feature {}

	-- For callbacks

	cb_help: PROCEDURE[TUPLE[IUP_FILE_DIALOG]]

	cb_file: FUNCTION[TUPLE[IUP_FILE_DIALOG, STRING, STRING], STRING]

	cb_button: FUNCTION[TUPLE[IUP_FILE_DIALOG, INTEGER, INTEGER, INTEGER, INTEGER, STRING], STRING]

	cb_motion: FUNCTION[TUPLE[IUP_FILE_DIALOG, INTEGER, INTEGER, STRING], STRING]

	cb_wheel: FUNCTION[TUPLE[IUP_FILE_DIALOG, REAL_32, INTEGER, INTEGER, STRING], STRING]

	-- Internal

	int_file_dialog: POINTER
		external "plug_in"
      alias "{
         location: "${sys}/plugins"
         module_name: "iup"
         feature_name: "IupFileDlg()"
         }"
      end

	-- Validations

	is_valid_type(type: STRING): BOOLEAN
		do
			if type.is_equal("OPEN") or
				type.is_equal("SAVE") or
				type.is_equal("DIR") then
				Result := True
			else
				Result := False
			end
		end
	
end

-- The MIT License (MIT)

-- Copyright (c) 2016, 2017, 2019 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
